package my.edu.model.User.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import my.edu.common.constant.MessageConstant;
import my.edu.common.domain.PageDTO;
import my.edu.common.domain.PageVO;
import my.edu.common.exception.AdminException;
import my.edu.common.exception.BillsException;
import my.edu.common.exception.CanNotFoundException;
import my.edu.common.exception.UserLoginException;
import my.edu.common.utils.PageUtils;
import my.edu.common.utils.RedisUtils;
import my.edu.model.User.entity.User;
import my.edu.model.User.entity.UserRole;
import my.edu.model.User.entity.VO.LoginDetailVO;
import my.edu.model.User.entity.VO.LoginVO;
import my.edu.model.User.entity.VO.UserVO;
import my.edu.model.User.entity.dto.LoginDTO;
import my.edu.model.User.entity.dto.RegisterDTO;
import my.edu.model.User.entity.dto.UserDTO;
import my.edu.model.User.entity.dto.UserSearchDTO;
import my.edu.model.User.mapper.PermissionMapper;
import my.edu.model.User.mapper.UserMapper;

import my.edu.security.password.PasswordEncoder;
import my.edu.security.password.PasswordUtils;
import my.edu.security.shiroservice.SysUserTokenService;
import my.edu.security.userEntity.UserDetail;
import my.edu.utils.RSAUtils;
import my.edu.utils.ThreadLocalUtil;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.task.ThreadPoolTaskExecutorBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    static String PWD123456="$2a$10$wtK.USMkc55NEiXXzeFEtOVB6TBlDhTkDhupmF9dLAx4BOj8SSnQy" ;

    @Autowired
    SysUserTokenService sysUserTokenService;
    @Autowired
    RedisUtils redisUtils;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    IUserRoleService userRoleService;

    @Autowired
    IRoleService roleService;

    @Autowired
    IPermissionService permissionService;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private ThreadPoolTaskExecutorBuilder threadPoolTaskExecutorBuilder;

    @Override
    public LoginVO login(LoginDTO loginDTO) throws Exception {
        User user = lambdaQuery().select()
                .eq(User::getUsername, loginDTO.getUsername())
                .one();
        if (user == null) {
            throw new UserLoginException(MessageConstant.USER_NOT_FOUND);
        }
        if (user.getStatus() == 0) throw new AdminException(MessageConstant.USER_NOT_ACTIVE);
        String rawPassword = RSAUtils.decrypt(loginDTO.getPassword(), (String) redisUtils.get("Rkey")); // 私钥解密
        if (!passwordEncoder.matches(rawPassword, user.getPassword())) {
            throw new UserLoginException(MessageConstant.PASSWORD_ERROR);
        }
        String token = sysUserTokenService.createToken(user.getId());
        setThreadLocalUserId(user.getId());
        LoginVO loginVO = new LoginVO();
        loginVO.setToken(token);
        List<String> roleName = roleService.getRoleNameByUserId(user.getId());

        LoginDetailVO build = LoginDetailVO.builder()
                .id(user.getId())
                .loginName(user.getName())
                .username(user.getUsername())
                .position(roleName)
                .build();
        loginVO.setLoginDetail(build);
        return loginVO;
    }

    private void setThreadLocalUserId(Long id) {
        ThreadLocalUtil.setCurrentId(id);
        // SecurityUtils.getSubject().getSession().setAttribute("userId", id);
    }

    @Override
    @Transactional
    public void register(RegisterDTO registerDTO) {
//        Role role = roleService.lambdaQuery()
//                .eq(Role::getId, registerDTO.getRoleId())
//                .one();
//        if (role == null) {
//            throw new RuntimeException("角色不存在");
//        }

        //校验用户名
        User one = lambdaQuery()
                .eq(User::getUsername, registerDTO.getUsername())
                .one();
        if (one != null) {
            throw new RuntimeException("用户名已存在");
        }
        //新增用户表
        User user = new User();
        BeanUtil.copyProperties(registerDTO, user);
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));//设置密码
        Long count = lambdaQuery().count();
        String number = String.format("U%04d", count + 1);//设置编号
        user.setNumber(number);
        save(user);
        setThreadLocalUserId(user.getId());
        //新增用户角色表
        //userRoleService.save(new UserRole(user.getId(), role.getId()));

    }

    @Override
    public PageVO<UserVO> listAllUser(PageDTO page, UserSearchDTO userSearchDTO) {
        Page<User> rowPage = new Page<>(page.getPage(), page.getSize());
        Page<User> list ;
        if (userSearchDTO== null){
           list = page(rowPage);
        }else {
             list = lambdaQuery()
                    .select()
                    .like(userSearchDTO.getUsername() != null && !userSearchDTO.getUsername().isEmpty()
                            , User::getUsername, userSearchDTO.getUsername())
                    .like( userSearchDTO.getName() != null && !userSearchDTO.getName().isEmpty()
                            , User::getName, userSearchDTO.getName())
                    .page(rowPage);
        }

        List<UserVO> voList = list.getRecords().stream().map(i -> {
            UserVO userVO = BeanUtil.copyProperties(i, UserVO.class);
            userVO.setRoleList(roleService.getRoleByUserId(i.getId()));
            return userVO;
        }).toList();
        return PageUtils.toPage(voList, list.getTotal());
    }

    @Override
    @Transactional
    public void updateUser(UserDTO userDTO) {
        UserDetail principal = (UserDetail) SecurityUtils.getSubject().getPrincipal();
        if (userDTO.getId() == 1 && principal.getId() != 1) throw new AdminException("不允许修改管理员信息");
        if (userDTO.getId() == 1 &&principal.getId() == 1 && !Objects.equals(userDTO.getUsername(), "admin"))
            throw new AdminException("管理员不允许修改自己的用户名");
        if (userDTO.getUsername().equals("admin")) throw new AdminException("不允许修改的用户名");

        checkUsername(userDTO);

        User user = getById(userDTO.getId());
        if (user == null) throw new CanNotFoundException(MessageConstant.CAN_NOT_FOUND);
        BeanUtil.copyProperties(userDTO, user, "id", "roles");
        //检查角色
        List<Long> roleIds = userDTO.getRoleId();
        if (CollUtil.contains(roleIds, 1L)) throw new AdminException("不允许修改成admin角色");
        //List<Role> roles = roleService.listByIds(roleIds);
        //删除原先的userrole
        userRoleService.remove(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getUserId, user.getId()));
        //新增新的userrole
        if (roleIds != null && !roleIds.isEmpty()) {
            List<UserRole> userRolelist = roleIds.stream().map(roleId -> new UserRole(user.getId(), roleId)).toList();
            userRoleService.saveBatch(userRolelist);
        }
        updateById(user);
    }

    @Override
    @Transactional
    public void reUserPwd(Map<String, Object> id) {
        Object idObj = id.get("id");
        if (idObj == null) {
            throw new UserLoginException("用户id不能为空");
        }
        Long idl;
        try {
            idl = Long.valueOf(idObj.toString());
        } catch (NumberFormatException e) {
            throw new UserLoginException("用户id必须是有效的数字");
        }

        if (idl < 1) {
            throw new UserLoginException("用户id必须大于0");
        }
        UserDetail principal = (UserDetail) SecurityUtils.getSubject().getPrincipal();
        if (idl == 1 && principal.getId() != 1) throw new AdminException("非管理员不允许修改管理员密码");
        lambdaUpdate().set(User::getPassword, PWD123456).eq(User::getId, idl).update();
    }

    @Override
    public UserVO getVOById(Long userId) {
        User user = getById(userId);
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        userVO.setRoleList(roleService.getRoleByUserId(userId));
        return userVO;
    }

    @Override
    public void saveUser(UserDTO userDTO) {
        checkUsername(userDTO);
        User user = BeanUtil.copyProperties(userDTO, User.class,"status","roleId");
        user.setStatus(1);
        user.setPassword(PasswordUtils.encode(123456+""));
        Long count = lambdaQuery().count();
        String number = String.format("U%04d", count + 1);//设置编号
        user.setNumber(number);
        save(user);
        List<Long> roleIds = userDTO.getRoleId();
        if (CollUtil.contains(roleIds, 1L)) throw new AdminException("不允许修改成admin角色");
        List<UserRole> userRolelist = roleIds.stream().map(roleId -> new UserRole(user.getId(), roleId)).toList();
        userRoleService.saveBatch(userRolelist);
    }

    @Override
    public void updateUserPwd(String oldpassword,String password) {
        UserDetail principal = (UserDetail) SecurityUtils.getSubject().getPrincipal();
        User one = lambdaQuery().eq(User::getId, principal.getId()).one();
        boolean matches = PasswordUtils.matches(oldpassword, one.getPassword());
        if (!matches)throw new UserLoginException("原密码错误！");
        String encode = PasswordUtils.encode(password);
        lambdaUpdate().set(User::getPassword, encode).eq(User::getId, principal.getId()).update();
    }

    @Override
    public void setStatus(List<Long> ids, Integer status) {
        if (ids.contains(1L))throw  new AdminException("管理员不可修改");
        lambdaUpdate().set(User::getStatus, status).in(User::getId, ids).update();
    }

    @Override
    public JSONArray listAllUserOnly() {
        List<User> list = list();
        JSONArray jsonArray = list.stream()
                .map(user -> {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("id", user.getId());
                    jsonObject.put("name", user.getName());
                    return jsonObject;
                })
                .collect(Collectors.toCollection(JSONArray::new));
        return jsonArray;
    }

    @Override
    public void checkUser(Long id) {
        User byId = getById(id);
        if (byId == null||byId.getStatus()==0) throw new BillsException(MessageConstant.USER_NOT_AVAILABLE);
    }

    @Override
    public String getPublicKey() throws NoSuchAlgorithmException {
        String pkey = (String) redisUtils.get("Pkey");
        if (pkey == null) {
            KeyPair keyPair = RSAUtils.genKeyPair();
            pkey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
            String priStr = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
            redisUtils.set("Pkey", pkey);
            redisUtils.set("Rkey", priStr);
            return pkey;
        } else {
            return pkey; // 已是 Base64 编码的公钥字符串
        }
    }

    private void checkUsername(UserDTO userDTO) {
        //校验用户名
        long count = count(Wrappers.<User>lambdaQuery()
                .eq(User::getUsername, userDTO.getUsername())
                .ne(User::getId, userDTO.getId()));
        if (count >0) {
            throw new UserLoginException("用户名已存在");
        }
    }


}
